package com.atguigu.gulimall.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.constant.ProductConstant;
import com.atguigu.common.to.SkuHasStockVO;
import com.atguigu.common.to.SkuReductionTO;
import com.atguigu.common.to.SpuBoundsTO;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.product.dao.SpuInfoDao;
import com.atguigu.gulimall.product.entity.*;
import com.atguigu.gulimall.product.feign.CouponFeignService;
import com.atguigu.gulimall.product.feign.SearchFeignService;
import com.atguigu.gulimall.product.feign.WareFeignService;
import com.atguigu.gulimall.product.service.*;
import com.atguigu.gulimall.product.vo.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private SearchFeignService searchFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * //TODO 高级部分完善
     *
     * @param spuSaveVO
     */
    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVO spuSaveVO) {
        //1、保存spu基本信息 ---> pms_spu_info
        SpuInfoEntity baseSpuInfo = this.saveBaseSpuInfo(spuSaveVO);

        //2、保存spu的描述图片 ---> pms_spu_info_desc
        this.saveSpuInfoDesc(spuSaveVO.getDecript(), baseSpuInfo, spuSaveVO);

        //3、保存spu的图片集 ---> pms_spu_images
        List<String> images = spuSaveVO.getImages();
        spuImagesService.saveImages(baseSpuInfo.getId(), images);

        //4、保存spu的规格参数（baseAttrs） ---> pms_product_attr_value
        this.saveProductAttrValue(baseSpuInfo, spuSaveVO);

        //5、保存spu的积分信息 ---> gulimall_sms > sms_spu_bounds
        Bounds bounds = spuSaveVO.getBounds();
        SpuBoundsTO spuBoundsTO = new SpuBoundsTO();
        BeanUtils.copyProperties(bounds, spuBoundsTO);
        spuBoundsTO.setSpuId(baseSpuInfo.getId());
        R saveSpuBoundsRel = couponFeignService.saveSpuBounds(spuBoundsTO);
        if (saveSpuBoundsRel.getCode() != 0) {
            log.error("远程保存spu积分信息失败");
        }

        //6、保存当前spu对应的所有sku信息
        List<Skus> skus = spuSaveVO.getSkus();

        if (CollectionUtils.isNotEmpty(skus)) {
            skus.forEach(sku -> {
                //6.1)、sku的基本信息 ---> pms_sku_info
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
//                private String skuName;
//                private BigDecimal price;
//                private String skuTitle;
//                private String skuSubtitle;
                //只复制了四个属性
                BeanUtils.copyProperties(sku, skuInfoEntity);

                skuInfoEntity.setBrandId(baseSpuInfo.getBrandId());
                skuInfoEntity.setCatalogId(baseSpuInfo.getCatalogId());
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSpuId(baseSpuInfo.getId());
                String skuDefaultImg = "";
                List<Images> skuImages = sku.getImages();
                //过滤没有图片路径的
                skuImages = skuImages.stream().filter(skuImage -> StringUtils.isNotBlank(skuImage.getImgUrl())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(skuImages)) {
                    for (Images imageItem : skuImages) {
                        if (imageItem.getDefaultImg() == 1) {
                            skuDefaultImg = imageItem.getImgUrl();
                            break;
                        }
                    }
                }
                skuInfoEntity.setSkuDefaultImg(skuDefaultImg);
                skuInfoService.saveSkuInfo(skuInfoEntity);

                //6.2)、sku的图片信息 ---> pms_sku_images
                List<SkuImagesEntity> skuImagesEntities = skuImages.stream().map(imageItem -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuInfoEntity.getSkuId());
                    skuImagesEntity.setImgUrl(imageItem.getImgUrl());
                    skuImagesEntity.setDefaultImg(imageItem.getDefaultImg());
                    skuImagesEntity.setImgSort(0);
                    return skuImagesEntity;
                }).collect(Collectors.toList());

                skuImagesService.saveBatch(skuImagesEntities);

                //6.3)、sku的销售属性信息 ---> pms_sku_sale_attr_value
                List<Attr> skuSaleAttrs = sku.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = skuSaleAttrs.stream().map(skuSaleAttr -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    skuSaleAttrValueEntity.setSkuId(skuInfoEntity.getSkuId());
                    skuSaleAttrValueEntity.setAttrId(skuSaleAttr.getAttrId());
                    skuSaleAttrValueEntity.setAttrName(skuSaleAttr.getAttrName());
                    skuSaleAttrValueEntity.setAttrValue(skuSaleAttr.getAttrValue());
                    skuSaleAttrValueEntity.setAttrSort(0);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

                //6.4)、sku的优惠、满减等信息 ---> gulimall_sms > sms_sku_full_reduction/sms_sku_ladder/sms_member_price
                //sms_sku_full_reduction
                SkuReductionTO skuReductionTO = new SkuReductionTO();
                BeanUtils.copyProperties(sku, skuReductionTO);
                skuReductionTO.setSkuId(skuInfoEntity.getSkuId());
                if (sku.getFullCount() > 0 ||
                        BigDecimal.ZERO.compareTo(sku.getDiscount()) == -1 ||
                        BigDecimal.ZERO.compareTo(sku.getFullPrice()) == -1 ||
                        BigDecimal.ZERO.compareTo(sku.getReducePrice()) == -1
                ) {
                    R saveReductionRel = couponFeignService.saveReduction(skuReductionTO);
                    if (saveReductionRel.getCode() != 0) {
                        log.error("远程保存sku的优惠、满减等信息失败");
                    }
                }
            });
        }
    }

    @Override
    public SpuInfoEntity saveBaseSpuInfo(SpuSaveVO spuSaveVO) {
        SpuInfoEntity baseSpuInfo = new SpuInfoEntity();
        BeanUtils.copyProperties(spuSaveVO, baseSpuInfo);
        baseSpuInfo.setCreateTime(new Date());
        baseSpuInfo.setUpdateTime(new Date());
        this.baseMapper.insert(baseSpuInfo);
        return baseSpuInfo;
    }

    @Override
    public void saveSpuInfoDesc(List<String> decript, SpuInfoEntity baseSpuInfo, SpuSaveVO spuSaveVO) {
        List<String> decripts = spuSaveVO.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(baseSpuInfo.getId());
        descEntity.setDecript(StringUtils.join(decripts, ","));
        spuInfoDescService.saveSpuInfoDesc(descEntity);
    }

    @Override
    public void saveProductAttrValue(SpuInfoEntity baseSpuInfo, SpuSaveVO spuSaveVO) {
        List<BaseAttrs> baseAttrs = spuSaveVO.getBaseAttrs();
        if (CollectionUtils.isNotEmpty(baseAttrs)) {
            List<ProductAttrValueEntity> productAttrValueEntities = baseAttrs.stream().map(baseAttr -> {
                ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
                productAttrValueEntity.setAttrId(baseAttr.getAttrId());
                AttrEntity attrEntity = attrService.getById(baseAttr.getAttrId());
                productAttrValueEntity.setAttrName(attrEntity.getAttrName());
                productAttrValueEntity.setAttrValue(baseAttr.getAttrValues());
                productAttrValueEntity.setQuickShow(baseAttr.getShowDesc());
                productAttrValueEntity.setSpuId(baseSpuInfo.getId());
                return productAttrValueEntity;
            }).collect(Collectors.toList());
            productAttrValueService.saveProductAttrValue(productAttrValueEntities);
        }
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> queryWrapper = new QueryWrapper<>();
        //key:
        //status: 0
        //brandId: 11
        //catelogId: 225
        String key = params.get("key") != null ? (String) params.get("key") : "";
        if (StringUtils.isNotBlank(key)) {
            //xxx from (spu_name like ? or id=?) and status = ? and brand_id=? and catalog_id=?
            queryWrapper.and(keyQueryWrapper -> {
                keyQueryWrapper.like("spu_name", key)
                        .or()
                        .eq("id", key);
            });
        }

        String status = params.get("status") != null ? (String) params.get("status") : "";
        if (StringUtils.isNotBlank(status)) {
            queryWrapper.eq("publish_status", status);
        }

        String brandId = params.get("brandId") != null ? (String) params.get("brandId") : "";
        if (StringUtils.isNotBlank(brandId)) {
            //如果是数字格式 ^\d{n,}$
            boolean isMatch = Pattern.matches("^\\d{1,}$", brandId);
            if (isMatch && Long.parseLong(brandId) > 0) {
                queryWrapper.eq("brand_id", brandId);
            }
        }

        String catelogId = params.get("catelogId") != null ? (String) params.get("catelogId") : "";
        if (StringUtils.isNotBlank(catelogId)) {
            queryWrapper.eq("catalog_id", catelogId);
        }

        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void spuUp(Long spuId) {//1、查出当前spuid对应的sku信息，品牌的名字
        List<SkuInfoEntity> skuInfoEntityList = skuInfoService.getSkusBySpuId(spuId);

        //需要上架的商品
        List<SkuEsModel> skuEsModels = new ArrayList<>();
        //TODO 4、查询当前sku所有可以被用来检索的规格属性，
        List<ProductAttrValueEntity> baseAttrs = productAttrValueService.baseListForSPU(spuId);
        List<Long> attrIds = baseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
        List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
        Set<Long> searchAttrIdSet = new HashSet<>();
        searchAttrIdSet.addAll(searchAttrIds);
        List<ProductAttrValueEntity> searchAttrs = baseAttrs.stream().filter(productAttrValueEntity ->
                searchAttrIdSet.contains(productAttrValueEntity.getAttrId())
        ).collect(Collectors.toList());

        List<SkuEsModel.Attrs> attrsList = searchAttrs.stream().map(productAttrValueEntity -> {
            SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
            attrs.setAttrId(productAttrValueEntity.getAttrId());
            attrs.setAttrName(productAttrValueEntity.getAttrName());
            attrs.setAttrValue(productAttrValueEntity.getAttrValue());
            return attrs;
        }).collect(Collectors.toList());


        //TODO 1、发送远程调用，库存系统查询是否有库存
        //默认为true
        Map<Long, Boolean> skuHashStockMap = skuInfoEntityList.stream().collect(Collectors.toMap(SkuInfoEntity::getSkuId, item -> true));
        try {
            List<Long> skuIdList = skuInfoEntityList.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
            R skuHasStockVOSR = wareFeignService.getSkusHasStock(skuIdList);
//          List<SkuHasStockVO> skuHasStockVOS = skuHasStockVOSR.getData();

            //自适应版本
//            List<Map<String, Object>> skuHasStockVOMapList = (List<Map<String, Object>>) skuHasStockVOSR.get("data");
//            List<SkuHasStockVO> skuHasStockVOS = convertSkuHasStockVOMap(skuHasStockVOMapList);

            //重构版本
            List<SkuHasStockVO> skuHasStockVOS = skuHasStockVOSR.getData(new TypeReference<List<SkuHasStockVO>>() {
            });

//        HashMap<Long,SkuHasStockVO> skuHasStockVOMap = new HashMap<>();
//        skuHasStockVOS.stream().forEach(skuHasStockVO -> {
//            skuHasStockVOMap.put(skuHasStockVO.getSkuId(),skuHasStockVO);
//        });
            skuHashStockMap = skuHasStockVOS.stream().collect(Collectors.toMap(SkuHasStockVO::getSkuId, SkuHasStockVO::getHasStock));
        } catch (Exception e) {
            log.error("库存服务查询异常,原因：", e);
        }

        //2、封装每个sku的信息
        Map<Long, Boolean> finalSkuHashStockMap = skuHashStockMap;
        skuEsModels = skuInfoEntityList.stream().map(sku -> {
            //组装需要的数据
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(sku, skuEsModel);

            //skuPrice skuImg hasStock hotScore brandName brandImg catalogName
            //    private List<Attrs> attrs;
            //
            //    @Data
            //    public static class Attrs {
            //        private Long attrId;
            //        private String attrName;
            //        private String attrValue;
            //    }
            skuEsModel.setSkuPrice(sku.getPrice());
            skuEsModel.setSkuImg(sku.getSkuDefaultImg());
            //TODO 1、发送远程调用，库存系统查询是否有库存
            skuEsModel.setHasStock(finalSkuHashStockMap.get(sku.getSkuId()));
            //TODO 2、热度评分。0
            skuEsModel.setHotScore(0L);
            //TODO 3、查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(sku.getBrandId());
            skuEsModel.setBrandName(brandEntity.getName());
            skuEsModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            skuEsModel.setCatalogName(categoryEntity.getName());
            //TODO 4、查询当前sku所有可以被用来检索的规格属性，
            skuEsModel.setAttrs(attrsList);

            return skuEsModel;
        }).collect(Collectors.toList());

        //TODO 5、发给ES进行保存
        R r = searchFeignService.productStatusUp(skuEsModels);
        if (r.getCode() == 0) {
            //远程调用成功
            //TODO 6、修改当前spu上架状态：publish_status
            this.baseMapper.updateSpuPublishStatus(spuId, ProductConstant.PublishStatusEnum.SPU_UP.getCode());
        } else {
            //远程调用失败
            //TODO 7、重复调用问题，接口幂等性；重试机制
            //Feign调用流程
            /*
             * 1、构造请求数据，将对象转为json
             * 2、发送请求进行执行（执行成功并且解码响应数据）
             * 3、执行请求会有重试机制
             */
        }
    }

    private List<SkuHasStockVO> convertSkuHasStockVOMap(List<Map<String, Object>> skuHasStockVOMap) {
        List<SkuHasStockVO> skuHasStockVOList = new ArrayList<>(skuHasStockVOMap.size());
        skuHasStockVOMap.forEach(skuHasStockMap -> {
            SkuHasStockVO stockVO = new SkuHasStockVO();

            Integer skuId = (Integer) skuHasStockMap.get("skuId");
            Boolean hasStock = (Boolean) skuHasStockMap.get("hasStock");
            stockVO.setSkuId(Long.parseLong(skuId.toString()));
            stockVO.setHasStock(hasStock);

            skuHasStockVOList.add(stockVO);
        });
        return skuHasStockVOList;
    }

}